package io.github.echarts.model.geometry;

/**
 * 表示二维平面上的矩形
 * 使用逻辑坐标系（左下角为原点，Y轴向上为正方向）
 */
public class Rectangle {
    
    /**
     * 矩形左下角X坐标
     */
    private final double x;
    
    /**
     * 矩形左下角Y坐标
     */
    private final double y;
    
    /**
     * 矩形宽度
     */
    private final double width;
    
    /**
     * 矩形高度
     */
    private final double height;
    
    /**
     * 创建矩形
     * 
     * @param x 左下角X坐标
     * @param y 左下角Y坐标
     * @param width 宽度
     * @param height 高度
     */
    public Rectangle(double x, double y, double width, double height) {
        this.x = x;
        this.y = y;
        this.width = Math.max(0, width);
        this.height = Math.max(0, height);
    }
    
    /**
     * 通过两点创建矩形（两点分别为左下角和右上角）
     * 
     * @param p1 第一个点
     * @param p2 第二个点
     * @return 新的矩形对象
     */
    public static Rectangle fromPoints(Point p1, Point p2) {
        double minX = Math.min(p1.getX(), p2.getX());
        double minY = Math.min(p1.getY(), p2.getY());
        double maxX = Math.max(p1.getX(), p2.getX());
        double maxY = Math.max(p1.getY(), p2.getY());
        
        return new Rectangle(minX, minY, maxX - minX, maxY - minY);
    }
    
    /**
     * 通过中心点和尺寸创建矩形
     * 
     * @param center 中心点
     * @param dimension 尺寸
     * @return 新的矩形对象
     */
    public static Rectangle fromCenter(Point center, Dimension dimension) {
        double halfWidth = dimension.getWidth() / 2;
        double halfHeight = dimension.getHeight() / 2;
        return new Rectangle(
            center.getX() - halfWidth,
            center.getY() - halfHeight,
            dimension.getWidth(),
            dimension.getHeight()
        );
    }
    
    /**
     * 创建一个指定位置和大小的正方形
     * 
     * @param x 左下角X坐标
     * @param y 左下角Y坐标
     * @param size 正方形边长
     * @return 新的正方形矩形对象
     */
    public static Rectangle square(double x, double y, double size) {
        return new Rectangle(x, y, size, size);
    }
    
    /**
     * 获取X坐标
     * 
     * @return 矩形左下角X坐标
     */
    public double getX() {
        return x;
    }
    
    /**
     * 获取Y坐标
     * 
     * @return 矩形左下角Y坐标
     */
    public double getY() {
        return y;
    }
    
    /**
     * 获取宽度
     * 
     * @return 矩形宽度
     */
    public double getWidth() {
        return width;
    }
    
    /**
     * 获取高度
     * 
     * @return 矩形高度
     */
    public double getHeight() {
        return height;
    }
    
    /**
     * 获取右边界X坐标
     * 
     * @return 矩形右边界X坐标
     */
    public double getRight() {
        return x + width;
    }
    
    /**
     * 获取上边界Y坐标
     * 
     * @return 矩形上边界Y坐标
     */
    public double getTop() {
        return y + height;
    }
    
    /**
     * 获取矩形中心点
     * 
     * @return 矩形中心点
     */
    public Point getCenter() {
        return new Point(x + width / 2, y + height / 2);
    }
    
    /**
     * 获取矩形尺寸
     * 
     * @return 矩形尺寸
     */
    public Dimension getDimension() {
        return new Dimension(width, height);
    }
    
    /**
     * 获取矩形面积
     * 
     * @return 矩形面积
     */
    public double getArea() {
        return width * height;
    }
    
    /**
     * 判断矩形是否包含指定点
     * 
     * @param point 要检查的点
     * @return 如果矩形包含该点，返回true，否则返回false
     */
    public boolean contains(Point point) {
        return contains(point.getX(), point.getY());
    }
    
    /**
     * 判断矩形是否包含指定坐标
     * 
     * @param px X坐标
     * @param py Y坐标
     * @return 如果矩形包含该坐标，返回true，否则返回false
     */
    public boolean contains(double px, double py) {
        return px >= x && px <= x + width && py >= y && py <= y + height;
    }
    
    /**
     * 判断此矩形是否与另一个矩形相交
     * 
     * @param other 另一个矩形
     * @return 如果两个矩形相交，返回true，否则返回false
     */
    public boolean intersects(Rectangle other) {
        return !(other.x > this.getRight() ||
                other.getRight() < this.x ||
                other.y > this.getTop() ||
                other.getTop() < this.y);
    }
    
    /**
     * 获取此矩形与另一个矩形的交集
     * 
     * @param other 另一个矩形
     * @return 交集矩形，如果没有交集，返回一个宽高为0的矩形
     */
    public Rectangle intersection(Rectangle other) {
        double ix = Math.max(this.x, other.x);
        double iy = Math.max(this.y, other.y);
        double iw = Math.min(this.getRight(), other.getRight()) - ix;
        double ih = Math.min(this.getTop(), other.getTop()) - iy;
        
        if (iw <= 0 || ih <= 0) {
            return new Rectangle(0, 0, 0, 0); // 没有交集
        }
        
        return new Rectangle(ix, iy, iw, ih);
    }
    
    /**
     * 获取包含此矩形和另一个矩形的最小矩形（并集的外接矩形）
     * 
     * @param other 另一个矩形
     * @return 并集的外接矩形
     */
    public Rectangle union(Rectangle other) {
        double ux = Math.min(this.x, other.x);
        double uy = Math.min(this.y, other.y);
        double uw = Math.max(this.getRight(), other.getRight()) - ux;
        double uh = Math.max(this.getTop(), other.getTop()) - uy;
        
        return new Rectangle(ux, uy, uw, uh);
    }
    
    /**
     * 创建一个新矩形，表示当前矩形按指定偏移量移动后的结果
     * 
     * @param deltaX X轴偏移量
     * @param deltaY Y轴偏移量
     * @return 移动后的新矩形
     */
    public Rectangle offset(double deltaX, double deltaY) {
        return new Rectangle(x + deltaX, y + deltaY, width, height);
    }
    
    /**
     * 创建一个新矩形，表示当前矩形按指定比例缩放后的结果（相对于矩形中心点缩放）
     * 
     * @param scale 缩放比例
     * @return 缩放后的新矩形
     */
    public Rectangle scale(double scale) {
        Point center = getCenter();
        double newWidth = width * scale;
        double newHeight = height * scale;
        double newX = center.getX() - newWidth / 2;
        double newY = center.getY() - newHeight / 2;
        return new Rectangle(newX, newY, newWidth, newHeight);
    }
    
    /**
     * 创建一个新矩形，表示当前矩形向四周扩展指定距离后的结果
     * 
     * @param amount 扩展距离
     * @return 扩展后的新矩形
     */
    public Rectangle expand(double amount) {
        return new Rectangle(x - amount, y - amount, width + amount * 2, height + amount * 2);
    }
    
    /**
     * 创建一个新矩形，表示当前矩形向四周扩展不同距离后的结果
     * 
     * @param left 向左扩展距离
     * @param bottom 向下扩展距离
     * @param right 向右扩展距离
     * @param top 向上扩展距离
     * @return 扩展后的新矩形
     */
    public Rectangle expand(double left, double bottom, double right, double top) {
        return new Rectangle(x - left, y - bottom, width + left + right, height + bottom + top);
    }
    
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        
        Rectangle rectangle = (Rectangle) o;
        
        if (Double.compare(rectangle.x, x) != 0) return false;
        if (Double.compare(rectangle.y, y) != 0) return false;
        if (Double.compare(rectangle.width, width) != 0) return false;
        return Double.compare(rectangle.height, height) == 0;
    }
    
    @Override
    public int hashCode() {
        int result;
        long temp;
        temp = Double.doubleToLongBits(x);
        result = (int) (temp ^ (temp >>> 32));
        temp = Double.doubleToLongBits(y);
        result = 31 * result + (int) (temp ^ (temp >>> 32));
        temp = Double.doubleToLongBits(width);
        result = 31 * result + (int) (temp ^ (temp >>> 32));
        temp = Double.doubleToLongBits(height);
        result = 31 * result + (int) (temp ^ (temp >>> 32));
        return result;
    }
    
    @Override
    public String toString() {
        return "Rectangle{" +
                "x=" + x +
                ", y=" + y +
                ", width=" + width +
                ", height=" + height +
                '}';
    }
} 